package io.noties.markwon.plugin.uml.model


class UmlClassMethod : AdapterItem {
    override lateinit var name: String
    var methodOrder: Int
    var visibility = Visibility.PRIVATE
    var isStatic = false
    var umlType: UmlType? = null
    var typeMultiplicity = TypeMultiplicity.SINGLE
    var arrayDimension = 1
    var parameters: ArrayList<MethodParameter>
        private set
    var parameterCount: Int

    constructor(
        name: String,
        methodOrder: Int,
        visibility: Visibility,
        aStatic: Boolean,
        umlType: UmlType?,
        typeMultiplicity: TypeMultiplicity,
        arrayDimension: Int
    ) {
        this.name = name
        this.methodOrder = methodOrder
        this.visibility = visibility
        isStatic = aStatic
        this.umlType = umlType
        this.typeMultiplicity = typeMultiplicity
        this.arrayDimension = arrayDimension
        parameters = ArrayList()
        parameterCount = 0
    }

    constructor(
        mName: String,
        methodOrder: Int,
        mVisibility: Visibility,
        mStatic: Boolean,
        mUmlType: UmlType?,
        mTypeMultiplicity: TypeMultiplicity,
        mArrayDimension: Int,
        mParameters: ArrayList<MethodParameter>,
        parameterCount: Int
    ) {
        name = mName
        this.methodOrder = methodOrder
        visibility = mVisibility
        isStatic = mStatic
        umlType = mUmlType
        typeMultiplicity = mTypeMultiplicity
        arrayDimension = mArrayDimension
        parameters = mParameters
        this.parameterCount = parameterCount
    }

    constructor(methodOrder: Int) {
        this.methodOrder = methodOrder
        parameterCount = 0
        parameters = ArrayList()
    }

    //return method name with conventional modifiers
    val methodCompleteString: String
        get() {
            //return method name with conventional modifiers
            var completeString = String()
            completeString =
                when (visibility) {
                    Visibility.PUBLIC -> "+"
                    Visibility.PROTECTED -> "~"
                    else -> "-"
                }
            completeString = "$completeString$name("
            for (p in parameters) {
                completeString += p.name
                if (parameters.indexOf(p) != parameters.size - 1) completeString =
                    "$completeString, "
            }
            completeString = "$completeString) : "
            completeString =
                when (typeMultiplicity) {
                    TypeMultiplicity.COLLECTION -> completeString + "<" + umlType!!.name + ">"
                    TypeMultiplicity.ARRAY -> completeString + "[" + umlType!!.name + "]^" + arrayDimension
                    else -> completeString + umlType!!.name
                }
            return completeString
        }

    fun findParameterByOrder(parameterOrder: Int): MethodParameter? {
        for (p in parameters) if (p.parameterOrder == parameterOrder) return p
        return null
    }

    fun getParameter(parameterName: String): MethodParameter? {
        for (p in parameters) if (p.name == parameterName) return p
        return null
    }

    //    **********************************************************************************************
    //    Modifiers
    //    **********************************************************************************************
    fun addParameter(parameter: MethodParameter) {
        parameters.add(parameter)
        parameterCount++
    }

    fun removeParameter(parameter: MethodParameter) {
        parameters.remove(parameter)
    }

    fun incrementParameterCount() {
        parameterCount++
    }

    //    **********************************************************************************************
    //    Test methods
    //    **********************************************************************************************
    fun containsParameterNamed(parameterName: String): Boolean {
        for (p in parameters) if ( p.name == parameterName) return true
        return false
    }

    fun isEquivalentTo(method: UmlClassMethod): Boolean {
        if (methodOrder == method.methodOrder) return false
        if (name != method.name) return false
        if (umlType != method.umlType) return false
        if (parameters.size != method.parameters.size) return false
        for (i in parameters.indices) {
            if (!parameters[i].isEquivalentTo(method.parameters[i])) return false
        }
        return true
    }

    companion object {
        const val JSON_CLASS_METHOD_NAME = "ClassMethodName"
        const val JSON_CLASS_METHOD_VISIBILITY = "ClassMethodVisibility"
        const val JSON_CLASS_METHOD_STATIC = "ClassMethodStatic"
        const val JSON_CLASS_METHOD_TYPE = "ClassMethodType"
        const val JSON_CLASS_METHOD_TYPE_MULTIPLICITY = "ClassMethodTypeMultiplicity"
        const val JSON_CLASS_METHOD_ARRAY_DIMENSION = "ClassMethodArrayDimension"
        const val JSON_CLASS_METHOD_PARAMETERS = "ClassMethodParameters"
        const val JSON_CLASS_METHOD_PARAMETER_COUNT = "ClassMethodParameterCount"
        const val JSON_CLASS_METHOD_INDEX = "ClassMethodIndex"
        fun indexOf(methodName: String, methods: ArrayList<UmlClassMethod>): Int {
            for (m in methods) if (methodName == m.name) return methods.indexOf(m)
            return -1
        }
    }
}
